home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 355_02 / slk2.exe / SPP / EXP.C < prev    next >
C/C++ Source or Header  |  1991-06-09  |  7KB  |  367 lines

  1. /*
  2.     New Sherlock preprocessor -- expression routines.
  3.  
  4.     Source:  exp.c
  5.     Started: September 28, 1987
  6.     Version:
  7.         July 15, 1988
  8.         February 15, 1989
  9.             periods removed from error messages.
  10.         June 22, 1989
  11.             curly_ok_flag kludge added to is_delim().
  12.  
  13.  
  14.     PUBLIC DOMAIN SOFTWARE
  15.  
  16.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  17.     the public domain on June 15, 1991, by its author,
  18.  
  19.         Edward K. Ream
  20.         166 North Prospect Ave.
  21.         Madison, WI 53705.
  22.         (608) 257-0802
  23.  
  24.     Sherlock may be used for any commercial or non-commercial purpose.
  25.  
  26.  
  27.     DISCLAIMER OF WARRANTIES
  28.  
  29.     Edward K. Ream (Ream) specifically disclaims all warranties,
  30.     expressed or implied, with respect to this computer software,
  31.     including but not limited to implied warranties of merchantability
  32.     and fitness for a particular purpose.  In no event shall Ream be
  33.     liable for any loss of profit or any commercial damage, including
  34.     but not limited to special, incidental consequential or other damages.
  35. */
  36.  
  37. #include "spp.h"
  38.  
  39. #undef TRACETOK
  40. #define TRACETOK(name) TICK(name)
  41.  
  42. /* Declare parsing routines defined in this file. */
  43. static void    exp_index(void);
  44. static void    exp_op(void);
  45. static void    exp_postop(void);
  46. static bool    exp_preop(void);
  47. static void    exp_term(void);
  48. static bool    is_delim(en_tokens delim);
  49.  
  50. /* =============== Externally visible routines =============== */
  51.  
  52. /*
  53.     Parse an expression, terminated by delim.
  54.     This routine is called recursively whenever '(' or '[' is seen.
  55. */
  56.  
  57. void
  58. con_expr(en_tokens delim)
  59. {
  60.     TRACEP("con_expr", printf("(%s)\n", pr_op(delim)));
  61.  
  62.     expr(delim);
  63. }
  64.  
  65. /*
  66.     Parse an expression, assumed to end with delim, but do NOT eat delim.
  67.     Null expressions are valid.  Comma operators are valid.
  68. */
  69. void
  70. expr(en_tokens delim)
  71. {
  72.     TRACEP("expr", printf("(%s)\n", pr_op(delim)));
  73.  
  74.     /* Check for null expression. */
  75.     if (is_delim(delim)) {
  76.         TRACEP("expr_end", printf("null expr: (%s)\n", pr_op(delim)));
  77.         return;
  78.     }
  79.  
  80.     for (;;) {
  81.         exp_term();
  82.         if(is_delim(delim)) {
  83.             break;
  84.         }
  85.         if (is_binop(token) || is(QUESTION_TOK) || is(COLON_TOK)) {
  86.             exp_op();
  87.         }
  88.         else {
  89.             err3(    "Binary or ternary operator expected at '",
  90.                 pr_tok(),
  91.                 "'");
  92.             if(needend(delim) == FALSE) {
  93.                 break;
  94.             }
  95.         }
  96.     }
  97.     TRACEP("expr_end", printf("(%s)\n", pr_op(delim)));
  98. }
  99.  
  100. /*
  101.     Parse an expression, assumed to end with delim or comma.
  102. */
  103. void
  104. expr1(en_tokens delim)
  105. {
  106.     TRACEP("expr1", printf("(%s)\n", pr_op(delim)));
  107.  
  108.     /* Check for null expression. */
  109.     if (is(COMMA_TOK) || is_delim(delim)) {
  110.         error("Null expression");
  111.         return;
  112.     }
  113.  
  114.     for (;;) {
  115.         exp_term();
  116.         if(is(COMMA_TOK) || is_delim(delim)) {
  117.             break;
  118.         }
  119.         if (is_binop(token) || is(QUESTION_TOK) || is(COLON_TOK)) {
  120.             exp_op();
  121.         }
  122.         else {
  123.             err3(    "Binary or ternary operator expected at '",
  124.                 pr_tok(),
  125.                 "'");
  126.             if(needend(delim) == FALSE) {
  127.                 break;
  128.             }
  129.         }
  130.     }
  131.     TRACEP("expr1_end", printf("(%s)\n", pr_op(delim)));
  132. }
  133.  
  134. /* ============== Internally visible routines =============== */
  135.  
  136. /*
  137.     Parse one or more array subscripts.
  138. */
  139. static void
  140. exp_index(void)
  141. {
  142.     TRACETOK("exp_index");
  143.  
  144.     while(is(LBRACK_TOK)) {
  145.         /* Eat the '[' */
  146.         get_token();
  147.         expr(RBRACK_TOK);
  148.         need(RBRACK_TOK);
  149.     }
  150. }
  151.  
  152. /*
  153.     Parse an infix (binary or ternary) operator.
  154. */
  155. static void
  156. exp_op(void)
  157. {
  158.     TRACETOK("exp_op");
  159.  
  160.     get_token();
  161. }
  162.  
  163. /*
  164.     Parse zero or one post operators.
  165. */
  166. static void
  167. exp_postop(void)
  168. {
  169.     TRACETOK("exp_postop");
  170.  
  171.     if (is(INC_TOK) || is(DEC_TOK)) {
  172.         /* Convert to post operators. */
  173.         get_token();
  174.     }
  175. }
  176.  
  177. /*
  178.     Parse a list of prefix operators:  unary op, prefix ++ or --, or casts.
  179.  
  180.     Return TRUE if a left paren was over-run.
  181. */
  182. static bool
  183. exp_preop(void)
  184. {
  185.  
  186.     TRACETOK("exp_preop");
  187.  
  188.     for (;;) {
  189.         if(is_unop(token) ||
  190.            is(PLUS_TOK) || is(MINUS_TOK) || is(STAR_TOK) ||
  191.            is(INC_TOK) || is(DEC_TOK)
  192.           ) {
  193.             get_token();
  194.         }
  195.         else if (is(LPAREN_TOK)) {
  196.             /* Eat the '(' */
  197.             get_token();
  198.             if (is_type()) {
  199.                 /* Parse the cast. */
  200.                 type_name();
  201.             }
  202.             else {
  203.                 return TRUE;
  204.             }
  205.         }
  206.         else {
  207.             return FALSE;
  208.         }
  209.     }
  210. }
  211.  
  212. /*
  213.     Parse a term:  pre op,  id part, post op.
  214.  
  215.     Call expr() recursively to handle array indices, function arguments and
  216.     parenthesized expressions.
  217.  
  218.     NOTE:    no semantic checks are done to make sure that a construction
  219.         makes sense in the context in which it appears.
  220.  
  221.     NOTE:  the following are all potentially valid id parts:
  222.  
  223.     
  224.     f(x) [25]
  225.     (*abc) (abc, xyz)
  226.     (*abc) [25]
  227.     0x25 (abc, xyz)
  228.     "abc" [25]
  229. */
  230. static void
  231. exp_term(void)
  232. {
  233.     bool lparen_seen;
  234.  
  235.     TRACETOK("exp_term");
  236.  
  237.     /* Sets over-run if went past a non-cast '(' */
  238.     lparen_seen = exp_preop();
  239.  
  240.     if (lparen_seen || is(ID_TOK) || is(INT_TOK) || is(LONG_TOK)) {
  241.  
  242.         if (lparen_seen) {
  243.             /* Eat the expression, which might be a pointer. */
  244.             expr(RPAREN_TOK);
  245.             need(RPAREN_TOK);
  246.         }
  247.         else {
  248.             /* Eat the id or constant. */
  249.             get_token();
  250.         }
  251.  
  252.         /* function calls and array subscripts are allowed. */
  253.         if (is(LPAREN_TOK)) {
  254.             /* Parse the list of actual parameters */
  255.             get_token();
  256.             expr(RPAREN_TOK);
  257.             need(RPAREN_TOK);
  258.         }
  259.         if (is(LBRACK_TOK)) {
  260.             exp_index();
  261.         }
  262.     }
  263.     else if (is(CHAR_TOK) || is(FLOAT_TOK)) {
  264.         /*
  265.             Character or floating CONSTANT.
  266.             No subscripting or function calls allowed.
  267.         */
  268.         get_token();
  269.     }
  270.     else if (is(STRING_TOK)) {
  271.         /* 
  272.             String constant.
  273.             Subscripting IS allowed.
  274.         */
  275.         get_token();
  276.         if (is(LBRACK_TOK)) {
  277.             exp_index();
  278.         }
  279.     }
  280.     else if (is(K_SIZEOF)) {
  281.         get_token();
  282.         if (is(LPAREN_TOK)) {
  283.             get_token();
  284.             type_name();
  285.         }
  286.         else {
  287.             exp_term();
  288.         }
  289.     }
  290.     exp_postop();
  291. }
  292.  
  293. /*
  294.     Return TRUE if token may validly appear in an expression.
  295.     Keywords, braces, and semicolons may not.
  296. */
  297. bool
  298. is_expr_tok(void)
  299. {
  300.     TRACETOK("is_expr_tok");
  301.  
  302.     if (    is_key(token) || is(SEMICOLON_TOK) ||
  303.         is(RCURLY_TOK) || is(LCURLY_TOK) ||
  304.         is(EOP_TOK)
  305.        ) {
  306.         return FALSE;
  307.     }
  308.     else {
  309.         return TRUE;
  310.     }
  311. }
  312.  
  313. /*
  314.     Return TRUE if we are at the end of an expression supposedly
  315.     delimited by delim.
  316.  
  317.     Semicolons and curly braces ALWAYS abort the expression.
  318.     Note that this is the same convention used by needend().
  319.     
  320.     Eat misplaced ')' and ']' tokens with a warning.
  321.  
  322.     Bug fix: 6/22/89:  Allow { or } if curly_ok_flag is TRUE;
  323. */
  324. static bool
  325. is_delim(en_tokens delim)
  326. {
  327.     TRACEP("is_delim", printf("(%s)\n", pr_op(delim)));
  328.  
  329.     for (;;) {
  330.         if (is(delim)) {
  331.             return TRUE;
  332.         }
  333.         else if (is(RPAREN_TOK) || is(RBRACK_TOK)) {
  334.             err3(    "Unmatched '",
  335.                 pr_tok(),
  336.                 "' in expression ignored");
  337.             get_token();
  338.         }
  339.         else if (is(EOP_TOK)) {
  340.             error("Unexpected end of file in expression");
  341.             return TRUE;
  342.         }
  343.         else if (    curly_ok_flag &&
  344.                 (is(RCURLY_TOK) || is(LCURLY_TOK))
  345.             ) {
  346.             /* { and } are also valid delimiters. */
  347.             return TRUE;
  348.         }
  349.         else if (is(RCURLY_TOK) ||
  350.              is(LCURLY_TOK) ||
  351.              is(SEMICOLON_TOK)
  352.             ) {
  353.  
  354.             err3(    "Unexpected '",
  355.                 pr_tok(), 
  356.                 "' in expression");
  357.  
  358.             /* Abort the expression. */
  359.             return TRUE;
  360.         }
  361.         else {
  362.             /* Not a delimiter. */
  363.             return FALSE;
  364.         }
  365.     }
  366. }
  367.